package com.fengmi.service.impl;

import com.fengmi.api.goods.GoodsApi;
import com.fengmi.dto.SearchDTO;
import com.fengmi.entity.ESGoods;
import com.fengmi.entity.SearchPageResult;
import com.fengmi.goods.MallGoods;
import com.fengmi.service.ISearchService;
import com.fengmi.vo.PageResultVO;
import com.fengmi.vo.ResultVO;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 作者：铁蛋
 * 时间：2021/10/18 17:57
 * 描述：永无Bug
 */
@Service
public class SearchServiceImpl implements ISearchService {
    @Autowired
    private GoodsApi goodsApi;
    @Autowired
    private ElasticsearchRestTemplate template;

    @Override
    public ResultVO goods2es() {
        //删除索引库
        template.deleteIndex(ESGoods.class);
        //创建索引库
        template.createIndex(ESGoods.class);
        template.putMapping(ESGoods.class);

        List<MallGoods> goodsAudited = goodsApi.findGoodsAudited();
        if (goodsAudited==null){
            return new ResultVO(false,"同步失败");
        }
        List<ESGoods> collect = goodsAudited.stream().map(spu -> {
            //spu->esGoods
            ESGoods esGoods = new ESGoods();
            esGoods.setSpuId(spu.getSpuId());

            esGoods.setBrandId(spu.getBrand().getId());
            esGoods.setBrandName(spu.getBrand().getName());


            esGoods.setCid1id(spu.getCat1().getId());
            esGoods.setCat1name(spu.getCat1().getName());
            esGoods.setCid2id(spu.getCat2().getId());
            esGoods.setCat2name(spu.getCat2().getName());
            esGoods.setCid3id(spu.getCat3().getId());
            esGoods.setCat3name(spu.getCat3().getName());

            esGoods.setCreateTime(new Date());
            esGoods.setGoodsName(spu.getGoodsName());
            esGoods.setPrice(spu.getPrice().doubleValue());
            if (spu.getAlbumPics() != null) {
                String[] imgArr = spu.getAlbumPics().split(",");
                if (imgArr != null && imgArr.length > 0) {
                    esGoods.setImageUrl(imgArr[0]);
                }
            }
            return esGoods;

        }).collect(Collectors.toList());
        template.save(collect);
        return new ResultVO(true,"同步成功");
    }

    @Override
    public PageResultVO<ESGoods> search(SearchDTO searchDTO) {
        //1.关键字复合查询
        if (searchDTO==null){
            return  new PageResultVO<>(false,"参数不合法");
        }
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(searchDTO.getKeyword())){
            MatchQueryBuilder goodsName = QueryBuilders.matchQuery("goodsName", searchDTO.getKeyword());
            MatchQueryBuilder brandName = QueryBuilders.matchQuery("brandName", searchDTO.getKeyword());
            MatchQueryBuilder cat3name = QueryBuilders.matchQuery("cat3name", searchDTO.getKeyword());
            boolQueryBuilder.should(goodsName).should(brandName).should(cat3name);
        }
        //2.分页查询
        PageRequest pageRequest=PageRequest.of((searchDTO.getPage()-1)>=0?searchDTO.getPage()-1:0, searchDTO.getSize());
        //3.按照商品的品牌和分类进行聚合
        TermsAggregationBuilder brandTermsAggregationBuilder = AggregationBuilders.terms("brand_agg")
                .field("brandName")
                .size(30);
        TermsAggregationBuilder cat3nameTermsAggregationBuilder = AggregationBuilders.terms("cat3name_agg")
                .field("cat3name")
                .size(30);

        //4.根据商品品牌和第三级分类进行过滤
        if (!StringUtils.isEmpty(searchDTO.getBrandNameFilter())){
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", searchDTO.getBrandNameFilter());

            boolQueryBuilder.filter(brandName);
        }
        if (!StringUtils.isEmpty(searchDTO.getCat3NameFilter())){
            TermQueryBuilder cat3name = QueryBuilders.termQuery("cat3name", searchDTO.getCat3NameFilter());

            boolQueryBuilder.filter(cat3name);
        }

        //5.按照价格排序
        FieldSortBuilder price = null;
        if (!StringUtils.isEmpty(searchDTO.getPriceSort())&& "desc".equals(searchDTO.getPriceSort())) {
             price = SortBuilders.fieldSort("price").order(SortOrder.DESC);

        }
        if (!StringUtils.isEmpty(searchDTO.getPriceSort())&& "asc".equals(searchDTO.getPriceSort())) {
             price = SortBuilders.fieldSort("price").order(SortOrder.ASC);

        }

        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                //设置分页

                .withPageable(pageRequest)
                //设置高亮
                .withHighlightBuilder(getHighlightBuilder("goodsName"))
                //设置聚合
                .addAggregation(brandTermsAggregationBuilder)
                .addAggregation(cat3nameTermsAggregationBuilder);
    //防止其空指针异常
        if (price!=null){
            builder.withSort(price);
        }
//                //指定排序方式
//                .withSort(price)
//                .build();


        SearchHits<ESGoods> search = template.search(builder.build(), ESGoods.class);
        SearchPageResult pageResultVO=new SearchPageResult();
        //获取总记录数
        long totalHits = search.getTotalHits();

        pageResultVO.setTotal(totalHits);
        //获取文档列表
        List<ESGoods> goodsList = search.getSearchHits().stream().map(hit -> {
            ESGoods esGoods = hit.getContent();
            //取高亮
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            highlightFields.forEach((k,v)->{
                String s = (v!=null&&v.size()>0)?v.get(0):"";
                if ("goodsName".equals(k)){
                    esGoods.setGoodsName(s);
                }
            });
            return esGoods;
        }).collect(Collectors.toList());
        //获取聚合信息
        Aggregations aggregations = search.getAggregations();
        Terms brand_agg = aggregations.get("brand_agg");
        List<? extends Terms.Bucket> buckets = brand_agg.getBuckets();
        List<String > brandNameList = buckets.stream().map(item -> (String)item.getKey()).collect(Collectors.toList());
        Terms cat3name_agg = aggregations.get("cat3name_agg");
        List<String > cat3nameList = cat3name_agg.getBuckets().stream().map(item ->(String) item.getKey()).collect(Collectors.toList());
        pageResultVO.setBrandNameList(brandNameList);
        pageResultVO.setCat3NameList(cat3nameList);

        pageResultVO.setData(goodsList);
        return pageResultVO;
    }

    @Override
    public ResultVO goodsToes(MallGoods spu) {
        if (spu == null){
            return new ResultVO(false,"同步失败");
        }
        //spu->esGoods
        ESGoods esGoods = new ESGoods();
        esGoods.setSpuId(spu.getSpuId());

        esGoods.setBrandId(spu.getBrand().getId());
        esGoods.setBrandName(spu.getBrand().getName());


        esGoods.setCid1id(spu.getCat1().getId());
        esGoods.setCat1name(spu.getCat1().getName());
        esGoods.setCid2id(spu.getCat2().getId());
        esGoods.setCat2name(spu.getCat2().getName());
        esGoods.setCid3id(spu.getCat3().getId());
        esGoods.setCat3name(spu.getCat3().getName());

        esGoods.setCreateTime(new Date());
        esGoods.setGoodsName(spu.getGoodsName());
        esGoods.setPrice(spu.getPrice().doubleValue());
        if (spu.getAlbumPics() != null) {
            String[] imgArr = spu.getAlbumPics().split(",");
            if (imgArr != null && imgArr.length > 0) {
                esGoods.setImageUrl(imgArr[0]);
            }
        }
        template.save(esGoods);
        return new ResultVO(true,"success");
    }

    // 设置高亮字段
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }
}
